package com.example.demo.config;

import com.example.demo.exception.*;
import com.example.demo.model.ApiResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import java.io.IOException;

/**
 * 全局异常处理类
 * <p>可以根据需要定义更多异常</p>
 * @author hankChan
 *         2017/7/13 0013.
 */
@ControllerAdvice
public class GlobalExceptionHandler extends WebMvcConfigurerAdapter implements ErrorController {

    static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    private static final String ERROR_PATH = "/error";

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false);
    }

    @RequestMapping(value = ERROR_PATH, produces = "application/json;charset=UTF-8")
    public ApiResult error() {
        return ApiResult.prepare().error(null, "500", "error");
    }

    /**
     * RequestParam的参数校验异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public @ResponseBody ApiResult constraintViolationException(ConstraintViolationException e) {
        return ApiResult.prepare().error(null, "", e.getConstraintViolations().stream().findFirst().get().getMessageTemplate());
    }

    /**
     * RequestBody的参数校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public @ResponseBody ApiResult methodArgumentNotValidException(MethodArgumentNotValidException e) {
        return ApiResult.prepare().error(null, "", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }

    @ExceptionHandler(UnauthorizedNotRedirectException.class)
    public @ResponseBody ApiResult unauthorizedNotRedirectException(UnauthorizedNotRedirectException e) {
        return ApiResult.prepare().error(null, e.getCode(), e.getMsg());
    }

    @ExceptionHandler(UnauthorizedException.class)
    public String unauthorizedException(HttpServletResponse response, UnauthorizedException unauthorizedException) {
        // TODO 捕获到未授权异常，跳转到授权页面
        String guideAuthUrl = "www.baidu.com";
        try {
            response.sendRedirect(guideAuthUrl);
            return null;
        } catch (IOException e) {
            throw new ApiException(unauthorizedException.getRequestId(), "跳转到授权页面时出错!");
        }
    }

    @ExceptionHandler(ApiException.class)
    public @ResponseBody ApiResult apiException(ApiException e) {
        return ApiResult.prepare().error(null, e.getCode(), e.getMsg());
    }

    @ExceptionHandler(BizException.class)
    public @ResponseBody ApiResult bizException(BizException e) {
        return ApiResult.prepare().error(null, e.getCode(), e.getMsg());
    }

    @ExceptionHandler(RpcException.class)
    public @ResponseBody ApiResult rpcException(RpcException e) {
        return ApiResult.prepare().error(null, e.getCode(), e.getMsg());
    }

    @ExceptionHandler(DaoException.class)
    public @ResponseBody ApiResult daoException(DaoException e) {
        return ApiResult.prepare().error(null, e.getCode(), e.getMsg());
    }

    @ExceptionHandler(SdkException.class)
    public @ResponseBody ApiResult sdkException(SdkException e) {
        return ApiResult.prepare().error(null, e.getCode(), e.getMsg());
    }

    @ExceptionHandler(TimeoutException.class)
    public @ResponseBody ApiResult timeoutException(TimeoutException e) {
        return ApiResult.prepare().error(null, e.getCode(), e.getMsg());
    }

    /**
     * 处理意料之外的异常
     * @return JSON格式响应结果
     */
    @ExceptionHandler(Exception.class)
    public @ResponseBody ApiResult unexpectedHandler(Exception e) {
        // 返回提示，服务器内部错误500
        return ApiResult.prepare().error(e.getMessage(), "500", "内部服务器异常!");
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }
}
